import math
import time

from application.config import DB
from application.http.models import OemModel, CodeModel
from sanren.extensions import MyLogger


log = MyLogger('push.job')


def push_job(*args, **kwargs):
    start_time = time.time()
    log.logger.info('=====主任务-推送码到品牌应用 START=====')

    # 获取生码单
    order = CodeModel.Order.find(args[0])
    if order is None:
        log.logger.info('=====Push Code: 找不到此生码单')
        return 700404

    # 生码单状态
    if order.status in (0, 1, 3, 4):
        log.logger.info('=====Push Code: 已经成功生码单才可以再进行推送码操作')
        return 700403

    # 开始推送脚本
    log.logger.info('=====Push Code: 开始推送码 START')

    # 品牌商 ID
    brand_id = order.brand.brand_id
    brand_code = order.company_code

    # Code 码表
    Code = CodeModel.get_code_model(brand_code)
    # OEM 码表
    OemCodeModel = OemModel.get_oem_code_model(brand_id)

    # 判断码此批次是不是已经同步过
    if OemCodeModel.where('batch_sn', order.batch_sn).first():
        log.logger.info('=====Push Code: 已经同步过的生码单,不需要再进行推送码操作')
        return 700403

    def fetch_in_batches(batch_size):
        # 初始化一个批次计数器
        count = 0
        while True:
            # 使用for循环迭代这个查询，因为它是惰性执行的
            obj_codes = Code.where('batch_num', order.batch_num).order_by('id', 'asc').offset(count * batch_size).limit(batch_size).get()
            for item in obj_codes:
                # 使用yield生成每一个结果
                yield item

            # 增加计数器
            count += 1

            # 如果没有更多的结果，则退出for循环
            if len(obj_codes) == 0:
                break

    # 处理码数据
    codes = []
    for item in fetch_in_batches(100000):
        temp = dict()
        temp['batch_sn'] = item.batch_sn
        temp['batch_num'] = item.batch_num
        temp['big_code'] = item.big_code if item.big_code else None
        temp['middle_code'] = item.middle_code if item.middle_code else None
        temp['small_code'] = item.small_code if item.small_code else None
        temp['serial_code'] = item.serial_code if item.serial_code else None
        temp['security_code'] = item.security_code if item.security_code else None
        temp['verify_code'] = item.verify_code if item.verify_code else None
        temp['status'] = item.status if item.status else 0
        codes.append(temp)
        # print(item.id)

    log.logger.info(f'=====Push Code: 推送码数量 {len(codes)}')

    connection = OemCodeModel.__connection__
    DB.begin_transaction(connection)
    # 开始生码
    try:
        DB.commit(connection)
        log.logger.info('=====Push Code 写数据库成功=====')

        limit_num = 100000
        if len(codes) > limit_num:
            for_num = math.ceil(len(codes) / limit_num)
            for i in range(for_num):
                OemCodeModel.bulk_create(codes[i * limit_num: (i + 1) * limit_num])
                log.logger.info(f'=====Push Code 分条写数据库, 当前第: {i}')
        else:
            OemCodeModel.bulk_create(codes)

        # raise Exception('测试出错') # 测试事务
    except Exception as e:
        # 异常
        DB.rollback(connection)
        log.logger.info('=====Push Code 出错啦=====')
        log.logger.info(repr(e))

    log.logger.info('=====Push Code: 开始推送码 END')
    process_time = time.time() - start_time
    log.logger.info(f'共用时: {process_time}')
    log.logger.info('=====主任务-推送码到品牌应用 END=====')


__all__ = [
    'push_job'
]
